<?php
/**
 * This class represents a Subversion project to be continuously integrated
 * 
 * @package Xinc.ModificationSet
 * @author David Ellis
 * @author Gavin Foster
 * @version 1.0
 * @copyright 2007 David Ellis, One Degree Square
 * @license  http://www.gnu.org/copyleft/lgpl.html GNU/LGPL, see license.php
 *	This file is part of Xinc.
 *	Xinc is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU Lesser General Public License as published by
 *	the Free Software Foundation; either version 2.1 of the License, or
 *	(at your option) any later version.
 *
 *	Xinc is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU Lesser General Public License for more details.
 *
 *	You should have received a copy of the GNU Lesser General Public License
 *	along with Xinc, write to the Free Software
 *	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
require_once 'Xinc/Logger.php';
require_once 'Xinc/ModificationSet/Interface.php';
require_once 'Xinc/Exception/ModificationSet.php';

class Xinc_ModificationSet_SVN implements Xinc_ModificationSet_Interface
{
	/**
	 * Directory containing the Subversion project.
	 *
	 * @var string
	 */
	private $directory = '.';
	
	/**
	 * Sets the svn checkout directory.
	 * 
	 * @param string
	 */
	public function setDirectory($directory)
	{
		$this->directory = $directory;
	}

	/**
   	 * Checks whether the Subversion project has been modified.
   	 * 
   	 * @return boolean
   	 */
	public function checkModified()
	{
		if (!file_exists($this->directory)) {
			throw new Xinc_Exception_ModificationSet('Subversion checkout directory not present');
		}
	
		$cwd = getcwd();
		chdir($this->directory);
		
		$output = '';
		$result = 9;
		exec('svn info', $output, $result);
		
		if ($result == 0) {
			$localSet = implode("\n",$output);

			$url = $this->getURL($localSet);
			
			$output = '';
			$result = 9;
			exec('svn info ' . $url, $output, $result);
			$remoteSet = implode("\n", $output);

			if ($result != 0) {
				throw new Xinc_Exception_ModificationSet('Problem with remote Subversion repository');
			}

			$localRevision = $this->getRevision($localSet);
			$remoteRevision = $this->getRevision($remoteSet);
			
			Xinc_Logger::getInstance()->debug("Subversion checkout dir is $this->directory local revision @ $localRevision Remote Revision @ $remoteRevision \n");
			chdir($cwd);
			return $localRevision < $remoteRevision;
		} else {
			chdir($cwd);
			throw new Xinc_Exception_ModificationSet('Subversion checkout directory is not a working copy.');
		}
	}

	/**
	 * Parse the result of an svn command for the Subversion project URL.
	 *
	 * @param string $result
	 * @return string
	 */
	private function getUrl($result)
	{
		$list = split("\n",$result);
		foreach ($list as $row) {
			$field = split(": ", $row);
			if (preg_match("/URL/",$field[0])) {
				return trim($field[1]);
			}
		}
	}

	/**
	 * Parse the result of an svn command for the Subversion project revision number. 
	 *
	 * @param string $result
	 * @return string
	 */
	function getRevision($result) {
		$list = split("\n",$result);
		foreach ($list as $row) {
			$field = split(":", $row);
			if (preg_match("/Revision/",$field[0])) {
				return trim($field[1]);
			}
		}
	}
	
	/**
  	 * Check necessary variables are set
  	 *
  	 * @throws Xinc_Exception_MalformedConfig
  	 */
  	public function validate()
  	{
  	    if (!isset($this->directory)) {
  	        throw new Xinc_Exception_MalformedConfig('Element modificationSet/svn - required attribute \'directory\' is not set');
  	    }
  	}
}
